/******************************************************************************
1：整个工程中不使用的串口，COMx_RXTX_BUFF_SIZE 修改为10 或更小


******************************************************************************/
#include "cpu.h"
#include "fifo.h"
#include "work.h"
#include "usart_driver.h"



struct COM_USART_S
{
	USART_TypeDef * USARTx;
	u8 IRQn;
	u32 rcc_perihp;
	GPIO_TypeDef *GPIO_tx;
	u16 pin_tx;
	GPIO_TypeDef *GPIO_rx;
	u16 pin_rx;

	GPIO_TypeDef *GPIO_opt;
	u16 pin_opt;

	u8 optional;

};


#define COM1_RXTX_BUFF_SIZE 10
static u8 com1_tx_buff[COM1_RXTX_BUFF_SIZE]={0};
static u8 com1_rx_buff[COM1_RXTX_BUFF_SIZE]={0};

#define COM2_RXTX_BUFF_SIZE 10
static u8 com2_tx_buff[COM2_RXTX_BUFF_SIZE]={0};
static u8 com2_rx_buff[COM2_RXTX_BUFF_SIZE]={0};

#define COM3_RXTX_BUFF_SIZE 100
static u8 com3_tx_buff[COM3_RXTX_BUFF_SIZE]={0};
static u8 com3_rx_buff[COM3_RXTX_BUFF_SIZE]={0};

#define COM4_RXTX_BUFF_SIZE 10
static u8 com4_tx_buff[COM4_RXTX_BUFF_SIZE]={0};
static u8 com4_rx_buff[COM4_RXTX_BUFF_SIZE]={0};

#define COM5_RXTX_BUFF_SIZE 10
static u8 com5_tx_buff[COM5_RXTX_BUFF_SIZE]={0};
static u8 com5_rx_buff[COM5_RXTX_BUFF_SIZE]={0};

#define COM6_RXTX_BUFF_SIZE 10
static u8 com6_tx_buff[COM6_RXTX_BUFF_SIZE]={0};
static u8 com6_rx_buff[COM6_RXTX_BUFF_SIZE]={0};

#define COM7_RXTX_BUFF_SIZE 10
static u8 com7_tx_buff[COM7_RXTX_BUFF_SIZE]={0};
static u8 com7_rx_buff[COM7_RXTX_BUFF_SIZE]={0};

#define COM8_RXTX_BUFF_SIZE 10
static u8 com8_tx_buff[COM8_RXTX_BUFF_SIZE]={0};
static u8 com8_rx_buff[COM8_RXTX_BUFF_SIZE]={0};



static struct FIFO_S com_fifo_tx[COM_MAX]={
	{.head=0, .tail=0, .size=COM1_RXTX_BUFF_SIZE, .buff=com1_tx_buff},\
	{.head=0, .tail=0, .size=COM2_RXTX_BUFF_SIZE, .buff=com2_tx_buff},\
	{.head=0, .tail=0, .size=COM3_RXTX_BUFF_SIZE, .buff=com3_tx_buff},\
	{.head=0, .tail=0, .size=COM4_RXTX_BUFF_SIZE, .buff=com4_tx_buff},\
	{.head=0, .tail=0, .size=COM5_RXTX_BUFF_SIZE, .buff=com5_tx_buff},\
	{.head=0, .tail=0, .size=COM6_RXTX_BUFF_SIZE, .buff=com6_tx_buff},\
	{.head=0, .tail=0, .size=COM7_RXTX_BUFF_SIZE, .buff=com7_tx_buff},\
	{.head=0, .tail=0, .size=COM8_RXTX_BUFF_SIZE, .buff=com8_tx_buff},\
};

static struct FIFO_S com_fifo_rx[COM_MAX]={
	{.head=0, .tail=0, .size=COM1_RXTX_BUFF_SIZE, .buff=com1_rx_buff},\
	{.head=0, .tail=0, .size=COM2_RXTX_BUFF_SIZE, .buff=com2_rx_buff},\
	{.head=0, .tail=0, .size=COM3_RXTX_BUFF_SIZE, .buff=com3_rx_buff},\
	{.head=0, .tail=0, .size=COM4_RXTX_BUFF_SIZE, .buff=com4_rx_buff},\
	{.head=0, .tail=0, .size=COM5_RXTX_BUFF_SIZE, .buff=com5_rx_buff},\
	{.head=0, .tail=0, .size=COM6_RXTX_BUFF_SIZE, .buff=com6_rx_buff},\
	{.head=0, .tail=0, .size=COM7_RXTX_BUFF_SIZE, .buff=com7_rx_buff},\
	{.head=0, .tail=0, .size=COM8_RXTX_BUFF_SIZE, .buff=com8_rx_buff},\
};

static struct COM_USART_S comx[COM_MAX]={
	{USART1, USART1_IRQn, RCC_APB2Periph_USART1, GPIOA,GPIO_Pin_9,  GPIOA,GPIO_Pin_10, GPIOA,GPIO_Pin_11},
	{USART2, USART2_IRQn, RCC_APB1Periph_USART2, GPIOA,GPIO_Pin_2,  GPIOA,GPIO_Pin_3 , GPIOA,GPIO_Pin_1 },
	{USART3, USART3_IRQn, RCC_APB1Periph_USART3, GPIOB,GPIO_Pin_10, GPIOB,GPIO_Pin_11, GPIOE,GPIO_Pin_15},
	{UART4,  UART4_IRQn,  RCC_APB1Periph_UART4,  GPIOC,GPIO_Pin_10, GPIOC,GPIO_Pin_11},
	{UART5,  UART5_IRQn,  RCC_APB1Periph_UART5,  GPIOC,GPIO_Pin_12, GPIOD,GPIO_Pin_2},
	{UART6,  UART6_IRQn,  RCC_APB1Periph_UART6,  GPIOB,GPIO_Pin_8 , GPIOB,GPIO_Pin_9},
	{UART7,  UART7_IRQn,  RCC_APB1Periph_UART7,  GPIOC,GPIO_Pin_2 , GPIOC,GPIO_Pin_3},
	{UART8,  UART8_IRQn,  RCC_APB1Periph_UART8,  GPIOC,GPIO_Pin_4 , GPIOC,GPIO_Pin_5},
};


static u8 com_data_send_check(E_COM index);


void com_usart_init(E_COM index,u32 BaudRate,u8 optional)
{
	GPIO_InitTypeDef  GPIO_InitStructure = {0};
	USART_InitTypeDef USART_InitStruct={0};
	NVIC_InitTypeDef  NVIC_InitStructure = {0};

	USART_TypeDef *USARTx;


	if(index>=COM_MAX)
		return;

	USARTx = comx[index].USARTx;

	switch(index)
	{
		case COM_USART1:
			RCC_APB2PeriphClockCmd( comx[index].rcc_perihp, ENABLE );
		break;
		case COM_UART6:
            RCC_APB1PeriphClockCmd( comx[index].rcc_perihp, ENABLE );
			GPIO_PinRemapConfig( GPIO_PartialRemap_USART6 , ENABLE );

		break;
		default:
			RCC_APB1PeriphClockCmd( comx[index].rcc_perihp, ENABLE );
		break;
	}

    GPIO_InitStructure.GPIO_Pin = comx[index].pin_tx;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init( comx[index].GPIO_tx, &GPIO_InitStructure );

    GPIO_InitStructure.GPIO_Pin = comx[index].pin_rx;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init( comx[index].GPIO_rx, &GPIO_InitStructure );

	comx[index].optional = optional;
	if( OPTIONAL_RS485 == optional)
	{
	    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Pin = comx[index].pin_opt;
		GPIO_Init( comx[index].GPIO_opt, &GPIO_InitStructure );
	}
	else if( OPTIONAL_CTS == optional)
	{
	    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Pin = comx[index].pin_opt;
		GPIO_Init( comx[index].GPIO_opt, &GPIO_InitStructure );
	}

	USART_InitStruct.USART_BaudRate = BaudRate;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No ;
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

	USART_Init(USARTx,&USART_InitStruct);

	USART_ITConfig( USARTx, USART_IT_TXE,  DISABLE );
	USART_ITConfig( USARTx, USART_IT_TC,   DISABLE );
	USART_ITConfig( USARTx, USART_IT_RXNE, ENABLE );

	NVIC_InitStructure.NVIC_IRQChannel = comx[index].IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure );

	USART_Cmd(USARTx,ENABLE);
	work_add_tail((void (*)(unsigned int data))com_data_send_check,index);
}
void com_usart_uninit(E_COM index)
{
	NVIC_InitTypeDef  NVIC_InitStructure = {0};
	GPIO_InitTypeDef  GPIO_InitStructure = {0};

	if(index>=COM_MAX)
		return;


	USART_Cmd(comx[index].USARTx,DISABLE);
	USART_ITConfig( comx[index].USARTx, USART_IT_TXE,  DISABLE );
	USART_ITConfig( comx[index].USARTx, USART_IT_RXNE, DISABLE );

	NVIC_InitStructure.NVIC_IRQChannel = comx[index].IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
    NVIC_Init( &NVIC_InitStructure );

	switch(index)
	{
		case COM_USART1:
			RCC_APB2PeriphClockCmd( comx[index].rcc_perihp, DISABLE );
		break;
		default:
			RCC_APB1PeriphClockCmd( comx[index].rcc_perihp, DISABLE );
		break;
	}

    GPIO_InitStructure.GPIO_Pin = comx[index].pin_tx;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init( comx[index].GPIO_tx, &GPIO_InitStructure );

    GPIO_InitStructure.GPIO_Pin = comx[index].pin_rx;
    GPIO_Init( comx[index].GPIO_rx, &GPIO_InitStructure );

	GPIO_InitStructure.GPIO_Pin = comx[index].pin_opt;
    GPIO_Init( comx[index].GPIO_opt, &GPIO_InitStructure );

}

static void com_rs485_send_enable(E_COM index)
{
	GPIO_WriteBit(comx[index].GPIO_opt, comx[index].pin_opt, Bit_SET);
}

static void com_rs485_receive_enable(E_COM index)
{
	GPIO_WriteBit(comx[index].GPIO_opt, comx[index].pin_opt, Bit_RESET);
}

static u8 com_data_send_check(E_COM index)
{
	struct FIFO_S * Q;

	if(index>=COM_MAX)
		return 0;

	Q=&com_fifo_tx[index];
	if(fifo_is_empty(Q))
		return 1;

	if(USART_GetFlagStatus( comx[index].USARTx, USART_FLAG_TXE ) && USART_GetFlagStatus( comx[index].USARTx, USART_FLAG_TC ) )
	{
		if(OPTIONAL_RS485 == comx[index].optional)
			com_rs485_send_enable(index);
		USART_ITConfig( comx[index].USARTx, USART_IT_TXE,  ENABLE );
	}
	return 0;
}

u16 com_send_data(E_COM index,const u8 * buff, u16 size)
{
	struct FIFO_S * Q;

	if(index>=COM_MAX)
		return 0;

	Q=&com_fifo_tx[index];
	size = fifo_set_data(Q,buff,size);

    return size;
}

struct FIFO_S * com_rx_fifo_get(E_COM index)
{
	if(index>=COM_MAX)
		return 0;
	return &com_fifo_rx[index];
}
struct FIFO_S * com_tx_fifo_get(E_COM index)
{
	if(index>=COM_MAX)
		return 0;
	return &com_fifo_tx[index];
}

void com_data_check(E_COM index)
{
	com_data_send_check(index);
}



static void com_IRQHandler(E_COM index)
{
	struct FIFO_S * Q;
	u8 data=0;

	if(USART_GetITStatus( comx[index].USARTx, USART_IT_TC ))
	{
		USART_GetFlagStatus(comx[index].USARTx, USART_IT_TC);
		USART_ITConfig( comx[index].USARTx, USART_IT_TC,  DISABLE );

		if(OPTIONAL_RS485 == comx[index].optional)
		{
			com_rs485_receive_enable(index);//this is at end!
		}
	}
	if(USART_GetITStatus( comx[index].USARTx, USART_IT_TXE ))
	{
		Q = &com_fifo_tx[index];
		if(fifo_is_empty(Q))
		{
			USART_ITConfig( comx[index].USARTx, USART_IT_TXE,  DISABLE );
			if(OPTIONAL_RS485 == comx[index].optional)
			{
				USART_ITConfig( comx[index].USARTx, USART_IT_TC,  ENABLE );
			}
		}
		else
		{
			data = fifo_get_data(Q,0);
			USART_SendData(comx[index].USARTx, data);
			USART_ClearITPendingBit(comx[index].USARTx, USART_IT_TC);
			fifo_head_offset( Q, 1);
		}
	}
	if(USART_GetITStatus(comx[index].USARTx, USART_IT_RXNE))
	{
		if( USART_GetFlagStatus(comx[index].USARTx, USART_FLAG_ORE)  ||\
			USART_GetFlagStatus(comx[index].USARTx, USART_FLAG_NE)	||\
			USART_GetFlagStatus(comx[index].USARTx, USART_FLAG_FE)	||\
			USART_GetFlagStatus(comx[index].USARTx, USART_FLAG_PE) ) // error!!!
		{
			USART_ReceiveData(comx[index].USARTx);
		}
		else
		{
			Q = &com_fifo_rx[index];
			data = USART_ReceiveData(comx[index].USARTx);
			fifo_set_data( Q, &data,1);
			USART_ClearITPendingBit(comx[index].USARTx,USART_IT_RXNE);
		}
	}
	if(USART_GetITStatus(comx[index].USARTx, USART_IT_CTS))
	{
		USART_ClearITPendingBit(comx[index].USARTx,USART_IT_CTS);
	}
}

void USART1_IRQHandler(void)
{
	com_IRQHandler(COM_USART1);
}
void USART2_IRQHandler(void)
{
	com_IRQHandler(COM_USART2);
}
void USART3_IRQHandler(void)
{
	com_IRQHandler(COM_USART3);
}

void UART4_IRQHandler(void)
{
	com_IRQHandler(COM_UART4);
}

void UART5_IRQHandler(void)
{
	com_IRQHandler(COM_UART5);
}
void UART6_IRQHandler(void)
{
	com_IRQHandler(COM_UART6);
}
void UART7_IRQHandler(void)
{
	com_IRQHandler(COM_UART7);
}
void UART8_IRQHandler(void)
{
	com_IRQHandler(COM_UART8);
}




